#include "inifile.h"
#include <cassert>
#include <cstdlib>
#include <string.h>
#include <fstream>
#include <cstdio>
#include "hilog.h"
#define MAX_INI_FILE_SIZE 1024 * 2

IniFile::IniFile()
{
    m_pfile = NULL;
    m_fileName = "";
    m_mapIniFile.clear();
}

IniFile::~IniFile(void)
{
    saveFile();
    m_mapIniFile.clear();
    m_fileName = "";
    m_pfile = NULL;
}

void IniFile::show_dgb_info(const string &section)
{
    MapIni::iterator it = m_mapIniFile.find(section);
    if (it != m_mapIniFile.end())
    {
        MapKeyValue map = it->second;
        MapKeyValue::iterator itKey = map.begin();
        while (itKey != map.end())
        {
            printf("show_dgb_info: \n"
                   "section: %s key: %s value:%s",section.c_str(),
                   itKey->first.c_str(), itKey->second.c_str());
            itKey++;
        }
    }
    else {
        printf("show_dgb_info: warn no seceion %s\n", section.c_str());
    }
}

void IniFile::readFile(const string& fileName)
{
    string strContent = "";
    string strSection = "";
    MapKeyValue mapKeyValue;
    mapKeyValue.clear();
    m_mapIniFile.clear();

    //if file not exist will create new file
    m_fileName = fileName;
    ifstream fin(m_fileName.c_str());
    while (getline(fin, strContent))
    {
        // printf("New line Read from file: %s\n", strContent.c_str());
        if (strContent[0] == '[')
        {// set section
            if (!mapKeyValue.empty())
            {
                m_mapIniFile[strSection] = mapKeyValue;
                mapKeyValue.clear();
                //printf("%s prase section: %s\n", m_fileName.c_str(),strSection.c_str());
            }
            int nRPos = strContent.find(']');
            strSection = strContent.substr(1, nRPos-1);
            //printf("section: %s-------ok1\n", strSection.c_str());
        }
        else if (strContent[0] == ';')
        {
            continue;
        }
        else if ((strContent[0] != ' ') && (strContent[0] != '\r') && (strContent[0] != '\n') && (strContent[0] != '\t'))
        {//set key value

            int nPos = strContent.find('=');
            int nLen = strContent.length();
            string strKey = strContent.substr(0, nPos);
            string strValue = strContent.substr(nPos+1, nLen-nPos-1);
            mapKeyValue[strKey]=strValue;
            //printf("prase: [%s]%s=%s\n", strSection.c_str(),strKey.c_str(), strValue.c_str());
        }
        else
        {
            printf("ignore this line.\n");
        }
    }

    if (strSection != "")
    {
        if (!mapKeyValue.empty())
        {
            m_mapIniFile[strSection] = mapKeyValue;
            mapKeyValue.clear();
            //printf("prase section: %s\n", strSection.c_str());
        }
    }   
    fin.close();
    return;
}

string IniFile::readStr(const string& section, const string& key, const string default_value)
{
	MapIni::iterator it = m_mapIniFile.find(section);
	if(it != m_mapIniFile.end())
	{
		MapKeyValue map = it->second;
		MapKeyValue::iterator itKey = map.find(key);
		if(itKey != map.end())
		{
			return itKey->second;
		}
	}
	return default_value;
}

int IniFile::readInt(const string &section, const string &key, int default_value)
{
	MapIni::iterator it = m_mapIniFile.find(section);
	if (it != m_mapIniFile.end())
	{
		MapKeyValue map = it->second;
		MapKeyValue::iterator itKey = map.find(key);
		if(itKey != map.end())
		{
			return atoi(itKey->second.c_str());
		}
	}

	return default_value;
}

bool IniFile::readBool(const string &section, const string &key, bool default_value)
{
	MapIni::iterator it = m_mapIniFile.find(section);
	if (it != m_mapIniFile.end())
	{
		MapKeyValue map = it->second;
		MapKeyValue::iterator itKey = map.find(key);
		if (itKey != map.end())
        {
            if(itKey->second == "true")
            {
                return true;
            }
            return false;
		}
        else {
            //printf("error: unfind [%s] %s\n", section.c_str(), key.c_str());
        }
	}
    else {
        //printf("error: unfind section %s\n", section.c_str());
    }

    return default_value;
}

long IniFile::readLong(const string &section, const string &key, long default_value)
{
    MapIni::iterator it = m_mapIniFile.find(section);
    if (it != m_mapIniFile.end())
    {
        MapKeyValue map = it->second;
        MapKeyValue::iterator itKey = map.find(key);
        if(itKey != map.end())
        {
            return atol(itKey->second.c_str());
        }
    }

    return default_value;
}

double IniFile::readDouble(const string &section, const string &key, double default_value)
{
    MapIni::iterator it = m_mapIniFile.find(section);
    if (it != m_mapIniFile.end())
    {
        MapKeyValue map = it->second;
        MapKeyValue::iterator itKey = map.find(key);
        if(itKey != map.end())
        {
            return atof(itKey->second.c_str());
        }
    }

    return default_value;
}

float IniFile::readFloat(const string &section, const string &key, float default_value)
{
    MapIni::iterator it = m_mapIniFile.find(section);
    if (it != m_mapIniFile.end())
    {
        MapKeyValue map = it->second;
        MapKeyValue::iterator itKey = map.find(key);
        if(itKey != map.end())
        {
            return atof(itKey->second.c_str());
        }
    }

    return default_value;
}

void IniFile::writeStr(const string &section, const string &key, const string & value)
{
	MapIni::iterator it = m_mapIniFile.find(section);
	if (it != m_mapIniFile.end())
	{
		MapKeyValue& map = it->second;
		MapKeyValue::iterator itKey = map.find(key);
		if (itKey != map.end())
		{
			itKey->second = value;
            //printf("modify value: [%s] %s=%s\n", section.c_str(), key.c_str(), value.c_str());
		}
		else
		{ // no find key
			map.insert(MapKeyValue::value_type(key, value));
			m_mapIniFile.insert(MapIni::value_type(section, map));
            //printf("new key value: [%s] %s=%s\n", section.c_str(), key.c_str(), value.c_str());
		}
	}
	else
	{// no find section
		MapKeyValue mapKey;
		mapKey.insert(MapKeyValue::value_type(key, value));
		m_mapIniFile.insert(MapIni::value_type(section, mapKey));

        //printf("new section: [%s] %s=%s\n", section.c_str(), key.c_str(), value.c_str());
	}

	return;
}

void IniFile::writeInt(const string &section, const string &key, int value)
{
	char sz [10];
	sprintf(sz, "%d", value);
	string strvalue = sz;
	writeStr(section, key, strvalue);
    return;
}

void IniFile::writeLong(const string &section, const string &key, long value)
{
    char sz [20];
    sprintf(sz, "%ld", value);
    string strvalue = sz;
    writeStr(section, key, strvalue);
    return;
}

void IniFile::writeDouble(const string &section, const string &key, double value)
{
    char sz [20];
    sprintf(sz, "%lf", value);
    string strvalue = sz;
    writeStr(section, key, strvalue);
    return;
}

void IniFile::writeFloat(const string &section, const string &key, float value)
{
    char sz [20];
    sprintf(sz, "%lf", value);
    string strvalue = sz;
    writeStr(section, key, strvalue);
    return;
}

void IniFile::writeBool(const string &section, const string &key, bool value)
{
	string strvalue;
	if (value)
	{
		strvalue = "true";
	}
	else
	{
		strvalue = "false";
	}

	writeStr(section, key, strvalue);
    return;
}

void IniFile::saveFile()
{
    int nCpPos = 0;
    char szIniBuf[MAX_INI_FILE_SIZE] = "\0";
    m_pfile = fopen(m_fileName.c_str(),"w");
    if (m_pfile)
    {
        MapIni::iterator itMapIni;
        for (itMapIni = m_mapIniFile.begin(); itMapIni != m_mapIniFile.end(); itMapIni++)
        {
            string strSection = itMapIni->first;
            //windows: \r\n linux: \n mac: \r
            string strSectionTrue = "["+strSection+"]\n";

            int nLen = strSectionTrue.length();
            memcpy(szIniBuf+nCpPos, strSectionTrue.c_str(), nLen);
            nCpPos = nCpPos+nLen;

            MapKeyValue map_key = itMapIni->second;
            MapKeyValue::iterator itKey;
            for(itKey = map_key.begin(); itKey != map_key.end(); itKey++)
            {
                string strKey = itKey->first;
                string strValue = itKey->second;
                string strKeyValue = strKey + "=" + strValue+"\n";
                int nValueLen = strKeyValue.length();

                memcpy(szIniBuf+nCpPos, strKeyValue.c_str(), nValueLen);
                nCpPos = nCpPos + nValueLen;
            }
        }

        fwrite(szIniBuf, 1, nCpPos, m_pfile);
        fclose(m_pfile);
    }
    else {
        printf("save %s failed.\n", m_fileName.c_str());
    }
}
